iT邦幫忙

2024 iThome 鐵人賽

DAY 28
0
Modern Web

一起來玩圖像編輯器:Fabric.js 的實戰修煉系列 第 28

Day28-fabric.js + React 的重構血淚三部曲(之二)-為什麼我的 component 瘋狂重新 render

  • 分享至 

  • xImage
  •  

接續昨天...
既然不能用 Redux 來存畫布,那畫布的部分我改成用 useContext 來存吧!
當下看起來,要在多個 component 裡使用、且不使用 Redux,好像也只能這麼做才能在多個 component 傳遞變數。

使用 useContext 的問題

當然,使用 useContext 有個明顯的問題,那就是:
所有在這個 context 裡的東西,只要 context 傳送的變數有改變,每個 component 都會重新 render

如果 context 中的值發生變化,所有消費該 context 的組件都會重新渲染。這是因為 React 需要確保所有依賴於 context 值的組件都能夠反映最新的狀態。

雖然畫布已用 context 傳送,但圖像操作的 function 散落在各個不同的 component裡,遇到不同 function 有交互關係的行為時,跨 component 不太容易寫邏輯。

所以後來將所有圖像操作的 function 全部集中,放到一支 custom hook 裡使用。

變數的頻繁改變,造成所有使用 context 的 component 也跟著頻繁render

前面有說到,使用的套件把 canvas本體、selectedObjects...等變數都視為是 state
畫布一有改變(任何形式的變化),會觸發  context  傳送新變數到各 component => 然後所有有使用此畫布的 component 都重新 render。

乍聽之下還好,但這件事在繪圖功能一多的時候,效能消耗就會變得倍數可怕。

效能消耗的例子:

假如我有十個不同繪圖功能的按鈕在畫面上(分屬於不同 componet 面板),
我分別在按鈕中引入 custom hook 中相應對的繪圖 function

每次畫布有改變的話,單個 component 會有的 render 順序:
 context改變 -> custom hook -> 單個 component
然後以上x10個 component

這就是每次畫布改變(就算裡只是選取物件)所有會 render 的物件 3*10 = 30次的(不必要) render

😱

小小的進行效能優化

這樣一定是不行的吧,至少加上 memo 或是 useCallback

最後是使用 React.memo(用在所有有使用畫布參數的component上) +useCallback(用在custom hook 裡的繪圖 function) ,來避免未使用到此 function 時,個別 component 的重新渲染。

更多關於性能優化:React 性能優化那件大事,使用 memo、useCallback、useMemo


re-render 的狀況實際上還是沒有改善很多

整體而言,目前就算加上 useCallback 或是 memo,每改變畫布一次還是會處發一些相關物件render,並不是最理想狀態。

直到發現其實改變 canvas 並不需要拿到 canvas 本體的最新變數,只要對他的記憶體空間處理就好...
是時候把套件拔掉了

明日待續


稍作整理一下,目前為止的架構:

畫布

-> 存在 context 裡,供全部 component 使用

圖像操作的 function (+ useCallback)

-> 全部放在一支 custom hook 裡,並在此 hook 中引入 context 的畫布

個別介面組件 (+ memo)

-> 引入 custom hook 裡的 個別繪圖 function 使用


上一篇
Day27-fabric.js + React 的重構血淚三部曲(之一)-要怎麼在 React 裡使用 fabric.js
下一篇
Day29-fabric.js + React 的重構血淚三部曲(之三)-參照本身還是記憶體空間?
系列文
一起來玩圖像編輯器:Fabric.js 的實戰修煉30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言